<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>第五章：Agents模块 - 思维导图</title>
    <style>
        body, html { margin: 0; padding: 0; height: 100%; overflow: hidden; font-family: sans-serif; }
        #mindmap-container { width: 100%; height: 100%; }
        .markmap-nav { position: absolute; bottom: 10px; right: 10px; } /* For navigation buttons if any */
    </style>
</head>
<body>
    <svg id="mindmap-container"></svg>
    <script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
    <script src="https://cdn.jsdelivr.net/npm/markmap-lib@0.15.4"></script>
    <script src="https://cdn.jsdelivr.net/npm/markmap-view@0.15.4"></script>

    <script type="text/template" id="markdown-content">
# 第五章：Agents模块

## 5.1 什么是Agent？
- **核心思想**: 利用LLM作为“大脑”或“推理引擎”
- **运行流程 (推理循环)**
  - 1. 接收用户输入 (Input)
  - 2. 构建提示 (Prompt Engineering)
    - 用户输入
    - 工具列表与描述
    - 历史交互
    - 特定指令格式 (如ReAct)
  - 3. LLM思考与决策 (Reasoning & Decision Making)
    - Thought (思考过程)
    - Action (行动决策)
    - Action Input (行动参数)
    - Final Answer (若可直接回答)
  - 4. 解析LLM输出 (Output Parsing)
    - 提取Action, Action Input
  - 5. 执行行动 (Tool Execution)
    - 调用工具函数
    - 获取Observation (观察结果)
  - 6. 反馈与迭代 (Feedback & Iteration)
    - Observation反馈给LLM
    - LLM再次思考决策
  - 7. 任务完成与最终输出 (Task Completion & Final Output)
    - 直到Final Answer或停止条件
- **特性**: 动态决策、灵活性、强大的问题解决能力

## 5.2 Agent的核心组件
- **Agent (Agent Class)**: 核心逻辑, 调用LLM决策
- **Tools (工具)**: 特定功能的函数/模块 (搜索引擎, 计算器等)
  - 需清晰名称和描述
- **Toolkits (工具包)**: 预封装的工具集合 (如SQLDatabaseToolkit)
- **AgentExecutor**: Agent的运行环境, 执行决策循环

## 5.3 Agent的类型
- **Zero-shot ReAct (`zero-shot-react-description`)**
  - 原理: 结合推理(Reasoning)和行动(Acting) (Thought, Action)
  - 特点: 仅根据工具描述决策 (Zero-shot), 通用, 对LLM推理要求高
- **Self-ask with search (`self-ask-with-search`)**
  - 原理: 无法直接回答时, 自问后续问题, 用搜索工具查找答案, 迭代
  - 特点: 结构简单, 目标明确, 适合问答和信息检索
- **Conversational ReAct (`conversational-react-description`)**
  - 原理: 类似Zero-shot ReAct, 但利用对话历史(Memory)
  - 特点: 适合聊天机器人, 多轮交互
- **Plan and execute**
  - 原理: 先制定计划 (一系列步骤), 然后逐个执行
  - 特点: 适合多步骤、有明确顺序的任务
- **选择依据**: 具体任务, LLM能力, 可用工具

## 5.4 使用Qwen模型创建Agent示例
- **通用设置**
  - 导入模块 (os, datetime, Tongyi, AgentType, Tool, ConversationBufferMemory, SerpAPIWrapper)
  - 初始化Qwen LLM (确保DASHSCOPE_API_KEY)
- **通用工具定义**
  - `get_current_date`: 获取当前日期
  - `simple_calculator`: 简单数学计算 (注意eval安全风险)
- **5.4.1 Zero-shot ReAct Agent示例**
  - 工具: `date_tool`, `calculator_tool`
  - 初始化: `initialize_agent` (AgentType.ZERO_SHOT_REACT_DESCRIPTION)
  - 运行与输出: 示例任务 (获取日期, 计算)
  - 思考过程示例
- **5.4.2 Self-ask with search Agent示例**
  - 工具: `SerpAPIWrapper` (需SERPAPI_API_KEY) 或 `mock_search`
    - 工具名: "Intermediate Answer" (重要)
  - 初始化: `initialize_agent` (AgentType.SELF_ASK_WITH_SEARCH)
  - 运行与输出: 示例任务 (法国首都, 《三体》作者)
  - 思考过程示例
- **5.4.3 Conversational ReAct Agent示例**
  - 工具: `date_tool`, `calculator_tool`
  - Memory: `ConversationBufferMemory` (memory_key="chat_history")
  - 初始化: `initialize_agent` (AgentType.CONVERSATIONAL_REACT_DESCRIPTION, memory)
  - 运行与输出: 多轮对话示例 (问候, 日期, 计算, 回忆名字)
  - 思考过程示例
- **代码和行为总体说明**
  - API密钥
  - 工具描述的重要性
  - `verbose=True` 调试
  - `handle_parsing_errors=True` 鲁棒性
  - LLM的适应性 (agent_kwargs)
  - Self-ask工具名
  - Conversational Agent的Memory类型

## 5.5 Agent的高级主题
- **自定义Agent**: 自定义Prompt模板和输出解析逻辑
- **Agent的错误处理**: `handle_parsing_errors`, 更精细机制
- **Agent与Memory的结合**: 实现上下文记忆
- **Agent的安全性**: 限制能力, 防范风险 (如避免eval)
- **工具的异步执行**: 提高性能

## 总结
- Agent是Langchain的强大模块
- 实现LLM与外部世界交互, 执行复杂任务
- 设计和调试具挑战性 (需理解LLM行为, Prompt, 工具交互)
- 建议: 多尝试, 观察verbose输出
    </script>
    <script>
      (async () => {
        // Ensure markmap is loaded. markmap-lib provides Transformer, markmap-view provides Markmap
        if (!window.markmap || !window.markmap.Markmap || !window.markmap.Transformer) {
          console.error('Markmap library (Markmap or Transformer) not loaded correctly. Ensure CDN scripts (markmap-lib and markmap-view) are accessible and loaded before this script.');
          const container = document.getElementById('mindmap-container');
          if (container) {
            container.innerHTML = '<p style="color:red; text-align:center; padding-top: 50px;">Error: Markmap library not loaded. Please check browser console for details.</p>';
          }
          return;
        }

        const { Markmap, Transformer } = window.markmap;
        const mindmapContainer = document.getElementById('mindmap-container');
        const markdownEl = document.getElementById('markdown-content');
        
        if (!markdownEl) {
          console.error('Markdown content element not found.');
          if (mindmapContainer) {
            mindmapContainer.innerHTML = '<p style="color:red; text-align:center; padding-top: 50px;">Error: Markdown source element not found.</p>';
          }
          return;
        }
        const markdown = markdownEl.textContent;

        if (!markdown || markdown.trim() === "") {
            console.error('Markdown content is empty.');
            if (mindmapContainer) {
                mindmapContainer.innerHTML = '<p style="color:red; text-align:center; padding-top: 50px;">Error: Markdown content is empty.</p>';
            }
            return;
        }

        const transformer = new Transformer();
        let rootData;
        try {
            rootData = transformer.transform(markdown); // transform returns { root, features }
        } catch (e) {
            console.error("Error transforming Markdown:", e);
            if (mindmapContainer) {
                mindmapContainer.innerHTML = `<p style="color:red; text-align:center; padding-top: 50px;">Error transforming Markdown: ${e.message}</p>`;
            }
            return;
        }

        if (!rootData || !rootData.root) {
            console.error('Failed to transform markdown into a root node. The "root" is undefined after transformation.');
            if (mindmapContainer) {
                mindmapContainer.innerHTML = '<p style="color:red; text-align:center; padding-top: 50px;">Error: Failed to process Markdown for the mind map (root node is undefined).</p>';
            }
            return;
        }

        try {
            // Pass the root node data (rootData.root) and optionally features (rootData.features) to Markmap.create
            // For basic usage, just rootData.root is often enough.
            const mm = Markmap.create(mindmapContainer, null, rootData.root);
            // mm.fit(); // fit is often called by default. Call if explicit control is needed.
        } catch (e) {
            console.error("Error creating or rendering Markmap:", e);
            if (mindmapContainer) {
                mindmapContainer.innerHTML = `<p style="color:red; text-align:center; padding-top: 50px;">Error rendering mind map: ${e.message}</p>`;
            }
        }
      })();
    </script>
</body>
</html>
